#include "semantic2.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
  
int offset = 0;

int scnt = 0, ucnt = 0;
char* symbols[MAX_SYMBOL_COUNT];
char* unqsybs[MAX_SYMBOL_COUNT];
Symbol* symbolTable[MAX_SYMBOL_COUNT];

int filled[MAX_SYMBOL_COUNT];


void Typee(Node* type, SNode* stype) {
    lexAssign(stype, type, BASICTYPE);
    // printf("%s\n", type->strval);
}
void ID(Node *id, SNode *sid) {
    lexAssign(sid, id, NAMEVAL);
    // printf("%s\n", id->strval);
}
void INT(Node* ival, SNode* sival) {
    lexAssign(sival, ival, CONSTANTINT);
    // printf("%d\n", ival->intval);
}
void FLOAT(Node* fval, SNode* sfval) {
    lexAssign(sfval, fval, CONSTANTFLOAT);
    // printf("%f\n", fval->floatval);
}

void Program(Node* program, SNode* sprogram) {
    // printf("Program\n");
    ExtdefList(program->ch[0], sprogram->ch[0]);
}

void ExtdefList(Node* extdefList, SNode* sextdefList) {
    if (extdefList == NULL) return ;
    // printf("ExtdefList\n");
    Extdef(extdefList->ch[0], sextdefList->ch[0]);
    ExtdefList(extdefList->ch[1], sextdefList->ch[1]);
}

void Extdef(Node* extDef, SNode* sextDef) {
    // printf("Extdef\n");
    Specifier(extDef->ch[0], sextDef->ch[0]); // get specifier
    switch (extDef->ch[1]->elem) {
        case SybExtDecList : 
            ExtDecList(extDef->ch[1], sextDef->ch[1]); 
        case SybSEMI : 
            break;
        case SybFunDec : 
            FunDec(extDef->ch[1], sextDef->ch[1]); 
            CompSt(extDef->ch[2], sextDef->ch[2]);
            break;
        default : 
            break;
    }

    switch (extDef->ch[1]->elem) {
        case SybExtDecList : 
            fillSymbols(sextDef->ch[0], sextDef->ch[1]);
            break;
        case SybSEMI : 
            fillStruct(sextDef->ch[0]);
            break;
        case SybFunDec : 
            fillFunctions(sextDef->ch[0], sextDef->ch[1]);
            break;
        default : 
            break;
    }
}

void ExtDecList(Node* extdecList, SNode* sextdecList) {
    // printf("ExtDecList\n");
    VarDec(extdecList->ch[0], sextdecList->ch[0]);
    if (extdecList->cnt > 1) {
        ExtDecList(extdecList->ch[2], sextdecList->ch[2]);
        sextdecList->nexDec = sextdecList->ch[2];
    }

    synAssign(sextdecList, sextdecList->ch[0], NAMEVAL);
    synAssign(sextdecList, sextdecList->ch[0], DATATYPE);
    if (extdecList->cnt > 1) {
        sextdecList->nexDec = sextdecList->ch[2];
    }
}

void Specifier(Node* specifier, SNode* sspecifier) {
    // printf("Specifier\n");
    switch (specifier->ch[0]->elem) {
        case SybTYPE : 
            Typee(specifier->ch[0], sspecifier->ch[0]); 
            break;
        case SybStructSpecifier : 
            StructSpecifier(specifier->ch[0], sspecifier->ch[0]); 
            break;
        default : 
            break;
    }

    synAssign(sspecifier, sspecifier->ch[0], NAMEVAL);
    synAssign(sspecifier, sspecifier->ch[0], DATATYPE);
}

void StructSpecifier(Node* structSpecifier, SNode* sstructSpecifier) {
    // printf("StructSpecifier\n");
    switch (structSpecifier->ch[1]->elem) {
        case SybOptTag :
            OptTag(structSpecifier->ch[1], sstructSpecifier->ch[1]);
            DefList(structSpecifier->ch[3], sstructSpecifier->ch[3]);
            break;
        case SybTag :
            Tag(structSpecifier->ch[1], sstructSpecifier->ch[1]);
            break;
        default : 
            break;
    }

    if (structSpecifier->cnt == 2) {
        int index = getSymbolIndex(sstructSpecifier->ch[1]->name);
        // printf("%d\n", index);
        if (index == -1 || !filled[index]) {
            serror(17, structSpecifier->ch[1]->lineno, "Undefined structure", sstructSpecifier->ch[1]->name);
            udfAssign(sstructSpecifier);
        } else {
            tabAssign(sstructSpecifier, index, DATATYPE);
        }
    } else {
        stuAssign(sstructSpecifier);
    }
}

void OptTag(Node* optTag, SNode* soptTag) {
    // printf("OptTag\n");
    if (optTag == NULL) return ;
    ID(optTag->ch[0], soptTag->ch[0]);

    synAssign(soptTag, soptTag->ch[0], NAMEVAL);
}

void Tag(Node *tag, SNode *stag) {
    // printf("Tag\n");
    ID(tag->ch[0], stag->ch[0]);

    synAssign(stag, stag->ch[0], NAMEVAL);
}

void VarDec(Node *varDec, SNode *svarDec) {
    // printf("VarDec\n");
    switch (varDec->cnt) {
        case 1 :
            ID(varDec->ch[0], svarDec->ch[0]);
            break;
        case 4 :
            VarDec(varDec->ch[0], svarDec->ch[0]);
            INT(varDec->ch[2], svarDec->ch[2]);
            break;
        default : 
            break;;
    }

    synAssign(svarDec, svarDec->ch[0], NAMEVAL);
    synAssign(svarDec, svarDec->ch[0], DATATYPE);
    if (varDec->cnt > 1) {
        if(svarDec->type == NULL) {
            lexAssign(svarDec, varDec->ch[2], ARRAYTYPE);
        } else {
            Type* arrayType = svarDec->type;
            while(arrayType->info.array.type != NULL) {
                arrayType = arrayType->info.array.type;
            }
            arrayType->info.array.type = malloc(sizeof(Type));
            arrayType->info.array.type->kind = ARRAY;
            arrayType->info.array.type->info.array.size = varDec->ch[2]->intval;
        }
    }
}

void FunDec(Node *funDec, SNode *sfunDec) {
    // printf("FunDec\n");
    ID(funDec->ch[0], sfunDec->ch[0]);
    if (funDec->cnt > 3) {
        VarList(funDec->ch[2], sfunDec->ch[2]);
    }

    synAssign(sfunDec, sfunDec->ch[0], NAMEVAL);
    if (funDec->cnt > 3) {
        synAssign(sfunDec, sfunDec->ch[2], ARGUMTYPE); // record first param
    }
}

void VarList(Node* varList, SNode* svarList) {
    // printf("VarList\n");
    ParamDec(varList->ch[0], svarList->ch[0]);
    if (varList->cnt > 1) {
        VarList(varList->ch[2], varList->ch[2]);
    }

    synAssign(svarList, svarList->ch[0], NAMEVAL);
    synAssign(svarList, svarList->ch[0], DATATYPE);

    if (varList->cnt > 1) {
        svarList->nexPar = svarList->ch[2];
    }
}

void ParamDec(Node* paramDec, SNode* sparamDec) {
    Specifier(paramDec->ch[0], sparamDec->ch[0]);
    VarDec(paramDec->ch[1], sparamDec->ch[1]);

    typeAssign(sparamDec->ch[0], sparamDec->ch[1]);
    synAssign(sparamDec, sparamDec->ch[1], NAMEVAL);
    synAssign(sparamDec, sparamDec->ch[1], DATATYPE);
    fillSymbol(sparamDec->name, sparamDec->type, 0); // insert when get
}

void CompSt(Node* compSt, SNode* scompSt) {
    DefList(compSt->ch[1], scompSt->ch[1]);
    StmtList(compSt->ch[2], scompSt->ch[2]);
}

void StmtList(Node* stmtList, SNode* sstmtList) {
    if (stmtList == NULL) return ;
    Stmt(stmtList->ch[0], sstmtList->ch[0]);
    StmtList(stmtList->ch[1], stmtList->ch[1]);
}

void Stmt(Node* stmt, SNode* sstmt) {
    // printf("Stmt\n");
    switch (stmt->cnt) {
        case 2 :
            Exp(stmt->ch[0], sstmt->ch[0]);
            break;
        case 1 :
            CompSt(stmt->ch[0], sstmt->ch[0]);
            break;
        case 3 :
            Exp(stmt->ch[1], sstmt->ch[1]);
            break;
        case 5 :
            Exp(stmt->ch[2], sstmt->ch[2]);
            Stmt(stmt->ch[4], sstmt->ch[4]);
            break;
        case 7 :
            Exp(stmt->ch[2], sstmt->ch[2]);
            Stmt(stmt->ch[4], sstmt->ch[4]);
            Stmt(stmt->ch[6], sstmt->ch[6]);
            break;
        default :
            break;
    }


    if (stmt->ch[0]->elem == SybRETURN) { // record return type
        Node* nd = stmt; SNode* snd = sstmt;
        while (nd->elem != SybExtdef) {
            nd = nd->pa;
            snd = snd->pa;
        }
        if (!isOptrandTypeSame(snd->ch[0], sstmt->ch[1])) {
            serror(8, stmt->ch[1]->lineno, "Type mismatched for return", "");
        }
    } else if (stmt->ch[0]->elem == SybIF || stmt->ch[0]->elem == SybWHILE) {
        if (!isOperandTypeInt(sstmt->ch[2])) {
            serror(99, stmt->ch[2]->lineno, "Only int type can be used as condition", "");
        }
    }
}

void DefList(Node* deflist, SNode* sdeflist) {
    if (deflist == NULL) return ;
    // printf("DefList\n");
    Def(deflist->ch[0], sdeflist->ch[0]);
    DefList(deflist->ch[1], sdeflist->ch[1]);

    synAssign(sdeflist, sdeflist->ch[0], DATATYPE);
    sdeflist->nexDec = sdeflist->ch[0]->nexDec;

    if (deflist->cnt > 0) {
        sdeflist->nexField = sdeflist->ch[1];
    }
}

void Def(Node* def, SNode* sdef) {
    // printf("Def\n");
    Specifier(def->ch[0], sdef->ch[0]);
    DecList(def->ch[1], sdef->ch[1]);

    Node* nd = def;
    while (nd->elem != SybCompSt && nd->elem != SybStructSpecifier) {
        nd = nd->pa;
    }

    if (nd->elem == SybStructSpecifier) {
        if (nd->cnt > 2) { // define a structure
            fillStructSymbols(sdef->ch[0], sdef->ch[1]);
        } else {
            // printf("no insert\n");
        }
    } else {
        if (sdef->ch[0]->type->kind != UNDEFINED) {
            fillSymbols(sdef->ch[0], sdef->ch[1]);
        }
    }
    synAssign(sdef, sdef->ch[0], DATATYPE);
    sdef->nexDec = sdef->ch[1];
}

void DecList(Node* decList, SNode* sdecList) {
    // printf("DecList\n");
    Dec(decList->ch[0], sdecList->ch[0]);
    if (decList->cnt > 1) {
        DecList(decList->ch[2], sdecList->ch[2]);
    }

    synAssign(sdecList, sdecList->ch[0], NAMEVAL);
    synAssign(sdecList, sdecList->ch[0], DATATYPE);

    if(decList->cnt > 1) {
        sdecList->nexDec = sdecList->ch[2];
    }
}

void Dec(Node* dec, SNode* sdec) {
    // printf("Dec\n");
    VarDec(dec->ch[0], sdec->ch[0]);
    if (dec->cnt > 1) {
        Exp(dec->ch[2], sdec->ch[2]);
    }

    if (dec->cnt > 1) {
        SNode* snd = sdec; Node* nd = dec;
        while(nd->elem != SybDef) { // get variable type
            nd = nd->pa;
            snd = snd->pa;
        }
        nd = nd->ch[0];
        snd = snd->ch[0]; // get specifier
        if (!isOptrandTypeSame(snd, sdec->ch[2])) {
            serror(5, dec->ch[1]->lineno, "Type mismatched for assignment", "");
        }
    }
    synAssign(sdec, sdec->ch[0], NAMEVAL);
    synAssign(sdec, sdec->ch[0], DATATYPE);
}

void Exp(Node* exp, SNode* sexp) {
    switch (exp->cnt) {
        case 3 :
            if (exp->ch[2]->elem == SybExp) {
                Exp(exp->ch[0], sexp->ch[0]);
                Exp(exp->ch[2], sexp->ch[2]);
            } else if (exp->ch[1]->elem == SybExp) { // (Exp)
                Exp(exp->ch[1], sexp->ch[1]);
            } else if (exp->ch[0]->elem == SybID) {
                ID(exp->ch[0], sexp->ch[0]);
            } else if (exp->ch[1]->elem == SybDOT) {
                Exp(exp->ch[0], sexp->ch[0]);
                ID(exp->ch[2], sexp->ch[2]);
            }
            break;
        case 2 :
            Exp(exp->ch[1], sexp->ch[1]);
            break;
        case 4 :
            if (exp->ch[2]->elem == SybArgs) {
                ID(exp->ch[0], sexp->ch[0]);
                Args(exp->ch[2], sexp->ch[2]);
            } else if(exp->ch[2]->elem == SybExp) {
                Exp(exp->ch[0], sexp->ch[0]);
                Exp(exp->ch[2], sexp->ch[2]);
            }
            break;
        case 1 :
            if (exp->ch[0]->elem == SybID) {
                ID(exp->ch[0], sexp->ch[0]);
            } else if (exp->ch[0]->elem == SybINT) {
                INT(exp->ch[0], sexp->ch[0]);
            } else {
                FLOAT(exp->ch[0], sexp->ch[0]);
            }
        default :
            break;
    }

    switch (exp->cnt) {
        case 1 :
            if (exp->ch[0]->elem == SybID) {
                int index = getSymbolIndex(sexp->ch[0]->name);
                if (index == -1 || !filled[index]) {
                    serror(1, exp->ch[0]->lineno, "Undefined variable", sexp->ch[0]->name);
                    udfAssign(sexp->ch[0]);
                } else {
                    tabAssign(sexp->ch[0], index, DATATYPE);
                }
            }
            synAssign(sexp, sexp->ch[0], NAMEVAL);
            synAssign(sexp, sexp->ch[0], DATATYPE);
            break;
        case 2 :
            if (exp->ch[0]->elem == SybMINUS) {
                if (!isOperandBasicType(sexp->ch[1])) {
                    serror(98, exp->ch[1]->lineno, "Unsupport operand type", "");
                }
                synAssign(sexp, sexp->ch[1], NAMEVAL);
                synAssign(sexp, sexp->ch[1], DATATYPE);
            } else { // NOT
                if (!isOperandTypeInt(sexp->ch[1])) {
                    serror(98, exp->ch[1]->lineno, "Unsupport operand type", "");
                }
                synAssign(sexp, sexp->ch[1], NAMEVAL);
                synAssign(sexp, sexp->ch[1], DATATYPE);
            }
            break;
        case 3 :
            if (isAsnOperator(exp->ch[1])) {
                if (!isLeftHandVar(sexp->ch[0])) {
                    serror(6, exp->ch[1]->lineno, "The left-hand side of an assignment must be a variable", "");
                }
                if (!isOptrandTypeSame(sexp->ch[0], sexp->ch[2])) {
                    serror(5, exp->ch[1]->lineno, "Type mismatched for assignment", "");
                }
                synAssign(sexp, sexp->ch[0], NAMEVAL);
                synAssign(sexp, sexp->ch[0], DATATYPE);
            }
            else if (isAlgOperator(exp->ch[1])) {
                if (!isOperandBasicType(sexp->ch[0]) || !isOperandBasicType(sexp->ch[2])) {
                    serror(98, exp->ch[1]->lineno, "Unsupport operand type", "");
                }
                if (!isOptrandTypeSame(sexp->ch[0], sexp->ch[2])) {
                    serror(7, exp->ch[1]->lineno, "Type mismatched for operands", "");
                }
                synAssign(sexp, sexp->ch[0], NAMEVAL);
                synAssign(sexp, sexp->ch[0], DATATYPE);
            } else if (isLogOperator(exp->ch[1])) {
                if(!isOperandTypeInt(sexp->ch[0]) || !isOperandTypeInt(sexp->ch[2])) {
                    if (!(sexp->ch[0]->type->kind == UNDEFINED || sexp->ch[2]->type->kind == UNDEFINED)) {
                        serror(99, exp->ch[1]->lineno, "Type mismatched for logical operator", "");
                    }
                }
                synAssign(sexp, sexp->ch[0], NAMEVAL);
                synAssign(sexp, sexp->ch[0], DATATYPE);
            } else if (exp->ch[0]->elem == SybLP) { // (exp)
                synAssign(sexp, sexp->ch[1], NAMEVAL);
                synAssign(sexp, sexp->ch[1], DATATYPE);
            } else if (exp->ch[1]->elem == SybLP) { // no args function
                int index = getSymbolIndex(sexp->ch[0]->name);
                // printf("index %d\n", index);
                if (index == -1 || !filled[index]) {
                    serror(2, exp->ch[0]->lineno, "Undefined function", sexp->ch[0]->name);
                    udfAssign(sexp->ch[0]);
                } else {
                    tabAssign(sexp->ch[0], index, DATATYPE);
                }
                synAssign(sexp, sexp->ch[0], NAMEVAL);
                synAssign(sexp, sexp->ch[0], DATATYPE);
            } else if (exp->ch[1]->elem == SybDOT) {
                if (!isVarStructure(sexp->ch[0])) {
                    serror(13, exp->ch[1]->lineno, "Illegal use of", ".");
                    udfAssign(sexp);
                } else if(!isFieldDefined(sexp->ch[0], sexp->ch[2])) {
                    printf("Error type 14 at Line %d: Non-existent field \"%s\"\n", exp->ch[2]->lineno, sexp->ch[2]->name);
                    udfAssign(sexp);
                } else {
                    synAssign(sexp, sexp->ch[2], NAMEVAL);
                    synAssign(sexp, sexp->ch[2], DATATYPE);
                }
            }
            break;
        case 4 :
            if (exp->ch[2]->elem == SybArgs) {
                int index = getSymbolIndex(sexp->ch[0]->name);
                if (index == -1 || !filled[index]) {
                    serror(2, exp->ch[0]->lineno, "Undefined function", sexp->ch[0]->name);
                    udfAssign(sexp->ch[0]);
                } else if (symbolTable[index]->type->kind != FUNC_BASIC) {
                    printf("Error type 11 at Line %d: \"%s\" is not a function\n", exp->ch[0]->lineno, sexp->ch[0]->name);
                } else {
                    tabAssign(sexp->ch[0], index, DATATYPE);
                    if (!checkFuncArgs(index, sexp->ch[2])) {
                        // serror(9, exp->ch[2]->lineno, "Function")
                        printf("Error type 9 at Line %d: Function \"%s", exp->ch[0]->lineno, sexp->ch[0]->name);
                        showArgs(symbolTable[index]->args);
                        printf("\" is not applicable for arguments \"");
                        showArgs(sexp->ch[2]);
                        printf("\"\n");
                    }
                }
                synAssign(sexp, sexp->ch[0], NAMEVAL);
                synAssign(sexp, sexp->ch[0], DATATYPE);
            } else if (exp->ch[1]->elem == SybLB) { // deep array @3
                if (sexp->ch[0]->type->kind != ARRAY) {
                    printf("Error type 10 at Line %d: \"%s\" is not an array\n", exp->ch[0]->lineno, sexp->ch[0]->name);
                    udfAssign(sexp);
                } else if (sexp->ch[2]->type->info.basic != BASIC_INT) {
                    printf("Error type 12 at Line %d: \"%lf\" is not an integer\n", exp->ch[2]->lineno, sexp->ch[2]->type->constant.floatval);
                    udfAssign(sexp);
                } else if (sexp->ch[0]->type->info.array.size <= sexp->ch[2]->type->constant.intval) {
                    serror(97, exp->ch[2]->lineno, "Array out of index", "");
                    udfAssign(sexp);
                } else {
                    synAssign(sexp, sexp->ch[0], NAMEVAL);
                    synAssign(sexp, sexp->ch[0], DATATYPE);
                    sexp->type = sexp->type->info.array.type;
                }
            }
            break;
    }
}

void Args(Node* args, SNode* sargs) {
    Exp(args->ch[0], sargs->ch[0]);
    if (args->cnt > 1) {
        Args(args->ch[2], sargs->ch[2]);
    }

    synAssign(sargs, sargs->ch[0], DATATYPE);
    if (args->cnt > 1) {
        sargs->nexPar = sargs->ch[2];
    }
}

void semanticAnalysis(Node* root) {
    SNode* sroot = getAllSymbol(root);
    sortSymbols();
    getUnqSymbol();

    // analysisTree(root, sroot);
    Program(root, sroot);

    // showSymblos();
}


/*******************************************************
 * error info reporter
 *******************************************************/
void serror(int type, int lineno, char *msg, char* sym) {
    if (strlen(sym) != 0) {
        printf("Error type %d at line %d: %s \"%s\"\n", type, lineno, msg, sym);
    } else {
        printf("Error type %d at line %d: %s\n", type, lineno, msg);
    }
}


/*******************************************************
 * printer
 * @showSymbols     show symbols
 * @showSymblos     show symbol table
 * @showSymbol      show info of a symbol in the table
//  * @println         divider printer
 * @showStructField show fileds of structure
 * @showArrayType   show array info
 * @showArgs        show arguments of function
 *******************************************************/
void showSymbols(char* sybs[], int cnt) {
    println();
    int i;
    for (i = 0; i < cnt; i++) {
        printf("%s\n", sybs[i]);
    }
}
void showSymblos() {
    int i;
    for (i = 0; i < ucnt; i++) {
        if(symbolTable[i] != NULL && filled[i]) {
            showSymbol(i);
        }
    }
}
void showSymbol(int index) {
    Symbol* symbol = symbolTable[index];
    printf("symbol name: %s\nsymbol type: ", symbol->name);

    switch (symbol->type->kind) {
        case BASIC : printf("basic %d\n", symbol->type->info.basic); break;
        // case ARRAY : printf("array "); showArrayType(symbol->type); printf("\n"); break;
        case FUNC_BASIC : printf("function %d ", symbol->type->info.basic); showArgs(symbol->args); printf("\n"); break;
        // case STRUCTTURE : printf("structure "); showStructField(symbol->name); printf("\n"); break;
        default : break;
    }
    
}
void println() {
    printf("----------------------------------\n");
}
void showStructField(char* name) {
    int index = getSymbolIndex(name);
    if (index == -1 || !filled[index]) {
        // printf("undefined\n");
        return ;
    }
    printf("{");
    SNode* field1 = symbolTable[index]->type->info.struc.field;
    SNode* field2;
    while (field1 != NULL) {
        field2 = field1->nexDec;
        while (field2 != NULL) {
            // printf("%x\n", field2);
            if (field2->fieldErr) {
                field2 = field2->nexDec;
                continue; 
            }
            printf("type %d %s", field2->type->info.basic, field2->name);
            field2 = field2->nexDec;
            if (field2 != NULL) printf("  ");
        }
        field1 = field1->nexField;
        if (field1 != NULL) printf(" ");
    }
    printf("}");
}
void showArrayType(Type* type) {
    while(type->kind != BASIC) {
        printf("[%d]", type->info.array.size);
        type = type->info.array.type;
    }
    printf(" %d", type->info.basic);
}
void showArgs(SNode* arg) {
    printf("(");
    while(arg != NULL) {
        switch (arg->type->kind) {
            case BASIC : 
                // printf("basic %d %s ", arg->type->info.basic, arg->name); 
                if (arg->type->info.basic == 0) printf("int");
                else printf("float");
                break;
            // case ARRAY : printf("array "); showArrayType(arg->type); printf(" "); break;
            default : break;
        }
        arg = arg->nexPar;
        if (arg != NULL) printf(", ");
    }
    printf(")");
}


/*******************************************************
 * symbol table creator
 *******************************************************/
SNode* getAllSymbol(Node* node) {
    /* insert into symbol table for declarations */
    switch (node->elem) {
        case 6: // OptTag
            insertSymbol(node->ch[0]->strval);
            break;
        case 8: // VarDec
            if (node->ch[0]->elem == 27) { // ID
                insertSymbol(node->ch[0]->strval);
            }
            break;
        case 9: // FunDec
            insertSymbol(node->ch[0]->strval);
            break;
        default:
        break;
    }
    SNode* snode = malloc(sizeof(SNode));
    snode->lineno = node->lineno;
    int i;
    for (i = 0; i < node->cnt; i++) {
        if (node->ch[i] != NULL) {
            SNode* ch = getAllSymbol(node->ch[i]);
            snode->ch[i] = ch;
            ch->pa = snode;
        }
    }
    return snode;
}
void insertSymbol(char* symbol) {
    symbols[scnt] = malloc(sizeof(char) * strlen(symbol));
    strcpy(symbols[scnt++], symbol);
}
void getUnqSymbol() {
    int i;
    unqsybs[ucnt++] = symbols[0];
    for (i = 1; i < scnt; i++) {
        if (strcmp(symbols[i], symbols[i - 1])) {
            unqsybs[ucnt++] = symbols[i];
        }
    }
}
void sortSymbols() {
    qsort(symbols, scnt, sizeof(char *), cmp);
}
int cmp(const void *s1, const void *s2) {
    return strcmp(*(char **)s1, *(char **)s2);
}


/*******************************************************
 * symbol table searcher
 *******************************************************/
int getSymbolIndex(char* name) {
    int l = 0, r = ucnt, mid;
    int cmpres;
    while (l < r) {
        mid = (l + r) >> 1;
        // printf("mid %d %s, %s\n", mid, unqsybs[mid], name);
        cmpres = strcmp(name, unqsybs[mid]);
        if (!cmpres) {
            break;
        } else {
            if (cmpres < 0) r = mid;
            else l = mid + 1;
        }
    }
    return l >= r ? -1 : mid;
}


/*******************************************************
 * symbol table filler
 * @fillError         report error info when filling
 * @fillSymbols       fill a list of symbols
 * @fillSymbol        fill a symbol into table
 * @fillStructSymbols fill a list of struct fileds
 * @fieldStruct       fill a field of struct into table
 * @fillFunctions     enclose of fillFunction
 * @fillfunction      fill a function symbol into table
 *******************************************************/
void fillError(int status, SNode* snode) {
    switch (status) {
        case SYMBOL_FILL_DONE : break;
        case SYMBOL_ALREADY_DECLARED : serror(3, snode->lineno, "Redefined variable", snode->name); break;
        case FUNCTION_ALREADY_DEFINED : serror(4, snode->lineno, "Redefined function", snode->name); break;
        case FIELD_ALREADY_DECLARED : snode->fieldErr = 1; serror(15, snode->lineno, "Redefined field", snode->name); break;
        case DUPLICATED_STRUCT_NAME : serror(16, snode->lineno, "Duplicated name", snode->name); break;
        case STRUCTTURE_NAME : serror(96, snode->lineno, "Name used as structure", snode->name); break;
        default : break;
    }
}
void fillSymbols(SNode* specifier, SNode* extdeclist) {
    int fillres;
    while(extdeclist != NULL) {
        typeAssign(specifier, extdeclist);
        fillError(fillSymbol(extdeclist->name, extdeclist->type, 0), extdeclist);
        extdeclist = extdeclist->nexDec;
    }
}
int fillSymbol(char* name, Type* type, int address) {
    // printf("fill symbol: %s\n", name);
    int index = getSymbolIndex(name);
    if (filled[index]) {
        if (!address) { 
            if (symbolTable[index]->type->kind == STRUCTTURE) return STRUCTTURE_NAME;
            else return SYMBOL_ALREADY_DECLARED;
        }
        else if (address == 1)return FIELD_ALREADY_DECLARED;
        else if (address == 2) return DUPLICATED_STRUCT_NAME;
    }

    symbolTable[index] = malloc(sizeof(Symbol));

    symbolTable[index]->name = name;
    symbolTable[index]->type = type;
    symbolTable[index]->address =address;

    filled[index] = 1;
    return SYMBOL_FILL_DONE;
}
void fillStructSymbols(SNode* specifier, SNode* extdeclist) {
    // printf("fill struct symbols\n");
    int fillres;
    while(extdeclist != NULL) {
        typeAssign(specifier, extdeclist);
        fillError(fillSymbol(extdeclist->name, extdeclist->type, 1), extdeclist);
        extdeclist = extdeclist->nexDec;
    }
}
void fillStruct(SNode* snode) {
    fillError(fillSymbol(snode->name, snode->type, 2), snode);
}
void fillFunctions(SNode* specifier, SNode* func) {
    fillError(fillFunction(specifier, func), func);
    SNode* param = func->nexPar;
}
int fillFunction(SNode* specifier, SNode* func) {
    typeAssign(specifier, func);
    int index = getSymbolIndex(func->name);
    if (filled[index]) return FUNCTION_ALREADY_DEFINED;

    symbolTable[index] = malloc(sizeof(Symbol));
    symbolTable[index]->name = func->name;
    symbolTable[index]->type = func->type;
    symbolTable[index]->args = func->nexPar;

    if (func->type->kind == BASIC) func->type->kind = FUNC_BASIC;
    else func->type->kind = FUNC_STRUCT;

    filled[index] = 1;
    return SYMBOL_FILL_DONE;
}


/*******************************************************
 * assigner
 * @typeAssign assign the type of specifier to variable 
 * @synAssign  assign the synthetic attribute of parent
 * @lexAssign  assign from lexcial value, for leaf node
 * @udfAssign  assign undefined type for error element
 * @tabAssign  assign from table symbol
 * @stuAssign  assign structure type for node
 *******************************************************/
void typeAssign(SNode* specifier, SNode* var) {
    if(var->type == NULL) {
        var->type = specifier->type;
    } else {
        Type* arrayType = var->type;
        while(arrayType->info.array.type != NULL) {
            arrayType = arrayType->info.array.type;
        }
        arrayType->info.array.type = specifier->type;
    }
}
void synAssign(SNode* pa, SNode* ch, int type) {
    switch (type) {
        case NAMEVAL:
            pa->name = ch->name;
            break;
        case DATATYPE :
            pa->type = ch->type;
            break;
        case ARRAYTYPE :
            pa->type->info.array.type = ch->type;
            break;
        case ARGUMTYPE :
            pa->nexPar = ch;
            break;
        default:
            break;
    }
}
void lexAssign(SNode* snode, Node* node, int type) {
    switch (type) {
        case NAMEVAL :
            snode->name = malloc(sizeof(char) * strlen(node->strval));
            strcpy(snode->name, node->strval);
            break;
        case BASICTYPE :
            snode->type = malloc(sizeof(Type));
            snode->type->kind = BASIC;
            if (node->strval[0] == 'i') {
                snode->type->info.basic = BASIC_INT;
            } else {
                snode->type->info.basic = BASIC_FLOAT;
            }
            break;
        case ARRAYTYPE :
            snode->type = malloc(sizeof(Type));
            snode->type->kind = ARRAY;
            snode->type->info.array.size = node->intval;
            break;
        case CONSTANTINT :
            snode->type = malloc(sizeof(Type));
            snode->type->kind = BASIC;
            snode->type->constant.intval = node->intval;
            snode->type->info.basic = BASIC_INT;
            break;
        case CONSTANTFLOAT :
            snode->type = malloc(sizeof(Type));
            snode->type->kind = BASIC;
            snode->type->constant.floatval = node->floatval;
            snode->type->info.basic = BASIC_FLOAT;
            break;
        default :
            break;
    }
}
void udfAssign(SNode* snode) {
    snode->type = malloc(sizeof(Type));
    snode->type->kind = UNDEFINED;
}
void tabAssign(SNode* snode, int index, int type) {
    switch (type) {
        case DATATYPE :
            snode->type = symbolTable[index]->type;
            break;
        default :
            break;
    }
}
void stuAssign(SNode* snode) {
    snode->type = malloc(sizeof(Type));
    snode->name = snode->ch[1]->name;
    snode->type->kind = STRUCTTURE;
    snode->type->info.struc.field = snode->ch[3];
}


/*******************************************************
 * operand chceker
 * 1. not support function return structure
 * 2. return true(no check) when operand is undefined 
 *******************************************************/
int isOptrandTypeSame(SNode* opt1, SNode* opt2) {
    if (opt1->type->kind == UNDEFINED || opt2->type->kind == UNDEFINED) return 1;
    if (opt1->type->kind != opt2->type->kind && opt2->type->kind != FUNC_BASIC) return 0;
    switch (opt1->type->kind) {
        case BASIC :
            return checkBasic(opt1, opt2); 
            break;
        case STRUCTTURE :
            return checkField(opt1, opt2);
            break; 
    }
    return 0;
}
int checkBasic(SNode* opt1, SNode* opt2) {
    return opt1->type->info.basic == opt2->type->info.basic;
}
int isOperandBasicType(SNode* opt) {
    if (opt->type->kind == UNDEFINED) return 1;
    return opt->type->kind == BASIC;
}
int isOperandTypeInt(SNode* opt) {
    if (opt->type->kind == UNDEFINED) return 1;
    return opt->type->kind == BASIC && opt->type->info.basic == BASIC_INT;
}
int isLeftHandVar(SNode* opt) {
    return opt->type->constant.intval == 0 && opt->type->constant.floatval == 0;
}


/*******************************************************
 * structure checker
 * 1. structure field must be declared in the same way
 *    or will not be regard as same
 * 2. checker is only valid for struct defined correctly  
 *******************************************************/
int isVarStructure(SNode* snode) {
    return snode->type->kind == STRUCTTURE;
}
int isFieldDefined(SNode* snode, SNode *field) {
    int index = getSymbolIndex(snode->name);
    if (index == -1 || !filled[index]) {
        return 0;
    }
    SNode* field1 = symbolTable[index]->type->info.struc.field;
    SNode* field2;
    while (field1 != NULL) {
        field2 = field1->nexDec;
        while (field2 != NULL) {
            // printf("field: %s", field2->name);
            if (!strcmp(field2->name, field->name)) {
                field->type = field2->type;
                return 1;
            }
            field2 = field2->nexDec;
        }
        field1 = field1->nexField;
    }
    return 0;
}
int checkField(SNode* opt1, SNode* opt2) {
    SNode* fieldx1 = opt1->type->info.struc.field;
    SNode* fieldy1 = opt2->type->info.struc.field;

    SNode *fieldx2, *fieldy2;
    while (fieldx1 != NULL && fieldy1 != NULL) {
        fieldx2 = fieldx1->nexDec;
        fieldy2 = fieldy1->nexDec;

        while (fieldx2 != NULL && fieldy2 != NULL) {
            if (fieldx2->type->info.basic != fieldy2->type->info.basic) return 0;
            fieldx2 = fieldx2->nexDec;
            fieldy2 = fieldy2->nexDec;
        }
        
        fieldx1 = fieldx1->nexField;
        fieldy1 = fieldy1->nexField;
    }
    // if (fieldx1 != NULL) {
        // printf("1 %s\n", fieldx1->nexDec->name);
    // }
    // if (fieldy1 != NULL) {
        // printf("2 %s\n", fieldy1->nexDec->name);
    // }
    if (fieldx1 != NULL || fieldy1 != NULL) return 0;
    return 1;
}


/*******************************************************
 * function arguments checker
 * *****************************************************/
int checkFuncArgs(int index, SNode* cargs) {
    SNode* args = symbolTable[index]->args;
    if (args == NULL) return 0;
    while (args != NULL && cargs != NULL) {
        if (!isOptrandTypeSame(args, cargs)) return 0;
        args = args->nexPar;
        cargs = cargs->nexPar;
    }
    if (args != NULL || cargs != NULL) return 0;
    return 1;
}


/*******************************************************
 * operator checker
 *******************************************************/
int isAlgOperator(Node* node) {
    return (
        node->elem == SybPLUS ||
        node->elem == SybMINUS ||
        node->elem == SybSTAR ||
        node->elem == SybDIV
    );
}
int isLogOperator(Node* node) {
    return (
        node->elem == SybAND ||
        node->elem == SybOR ||
        node->elem == SybNOT ||
        node->elem == SybRELOP
    );
}
int isAsnOperator(Node* node) {
    return (
        node->elem == SybASSIGNOP 
    );
}
